#include "sps_config.h"

SpsLog*    SpsLog::log_           = NULL;
FILE*      SpsLog::file_          = NULL;
bool       SpsLog::destroyed_     = false;


static const char *errlevels[] = {
  "emerg", "alert", "crit", "error", "warn", "info", "debug"
};

#define LOG_ERROR_FILE    "error.log"
#define LOG_MAX_LENGTH    (2 * 1024)

SpsLog& SpsLog::instance()
{
  if (!log_) {
    if (destroyed_) {
      onDeadReference();
    } else {
      onCreate();
    }
  }

  return *log_;
}

bool SpsLog::openLog(const char *path)
{
  char filename[1024], *p, *name;
  size_t plen, nlen;

  if (path == NULL) {
    name = (char *)LOG_ERROR_FILE;
  } else {
    p = (char *)strrchr(path, '\\');
    if (p == NULL) {
      name = (char *)LOG_ERROR_FILE;
    } else {
      plen = (size_t)(p - path + 1);
      memcpy(filename, path, plen);
      memcpy(filename + plen, LOG_ERROR_FILE, sizeof(LOG_ERROR_FILE));
      name = filename;
    }
  }

  file_ = _fsopen(name, "a+", _SH_DENYWR);
  if (!file_) {
    return false;
  }

  return true;
}

void SpsLog::closeLog()
{
  if (file_) {
    fclose(file_);
    file_ = NULL;
  }
}

void SpsLog::logEmerg(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_EMERG, fmt, args);
  va_end(args);
}

void SpsLog::logAlert(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_ALERT, fmt, args);
  va_end(args);
}

void SpsLog::logCrit(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_CRIT, fmt, args);
  va_end(args);
}

void SpsLog::logError(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_ERROR, fmt, args);
  va_end(args);
}

void SpsLog::logWarn(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_WARN, fmt, args);
  va_end(args);
}

void SpsLog::logInfo(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_INFO, fmt, args);
  va_end(args);
}

void SpsLog::logDebug(const char *fmt, ...)
{
  va_list args;

  va_start(args, fmt);
  logCore(LOG_DEBUG, fmt, args);
  va_end(args);
}

void SpsLog::logStderr(const char *fmt, ...)
{
  char    errstr[LOG_MAX_LENGTH];
  size_t  len, max;
  va_list args;

  max = LOG_MAX_LENGTH - 1;
  len = 0;

  va_start(args, fmt);
  len += vsnprintf(errstr, max - len, fmt, args);
  va_end(args);

  if (len >= max) {
    len = max;
  }

  errstr[len++] = 0;

  std::cerr <<errstr <<std::endl;
}


/*********************************************************
 * Private functions                                     *
 ********************************************************/
 
 
SpsLog::SpsLog()
{
	
}

SpsLog::~SpsLog()
{

}

SpsLog::SpsLog(const SpsLog& rhs)
{
	
}


SpsLog& SpsLog::operator=(const SpsLog& rhs)
{
  return *log_;
}

void SpsLog::onCreate()
{
  static SpsLog log;

  log_ = &log;
}

void SpsLog::onDeadReference()
{
  /* TODO: Recreate if log_ is destroyed. */
}


void SpsLog::logCore(int level, const char *fmt, va_list args)
{
  char errstr[LOG_MAX_LENGTH];
  size_t len, max;
  SYSTEMTIME st;

  if (!file_) {
    return;
  }

  max = LOG_MAX_LENGTH - 1;
  len = 0;

  GetLocalTime(&st);
  len += snprintf(errstr + len, max - len,
		  "%4d-%02d-%02d %02d:%02d:%02d.%03d %ld#%ld [%s] ",
		  st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute,
		  st.wSecond, st.wMilliseconds, getpid(), gettid(),
		  errlevels[level]);

  len += vsnprintf(errstr + len, max - len, fmt, args);
  
  if (len >= max) {
    len = max;
  }

  errstr[len++] = '\n';
  errstr[len] = 0;

  fprintf(file_, errstr);
  fflush(file_);
}
